//
//  ThreadVC.m
//  SYPerfectDemo
//
//  Created by Lssyyy on 2018/4/28.
//  Copyright © 2018年 Lssyyy. All rights reserved.
//
// ---------------------------------------------------------
//  区别     |    并发队列   |  串行队列  |  主队列  |
// ---------------------------------------------------------
//同步(sync) | 没有开启新线程，串行执行任务 |   没有开启新线程，串行执行任务    |  主线程调用：死锁卡住不执行,其他线程调用：没有开启新线程，串行执行任务  |
// ---------------------------------------------------------
//异步(async)|  有开启新线程，并发执行任务  |  有开启新线程(1条)，串行执行任务  |  没有开启新线程，串行执行任务  |
// ---------------------------------------------------------

#import "ThreadVC.h"

@interface ThreadVC ()
@property (nonatomic,strong) UITextView *textView;
@end

@implementation ThreadVC
- (UITextView *)textView{
    if (!_textView) {
        _textView = [[UITextView alloc]initWithFrame:CGRectMake(0, 0,self.view.width, 100)];
        _textView.textColor = [UIColor blackColor];
        _textView.text = @"爱的世界卡死了快记录卡时间到了卡死了快的将拉开爱的世界卡死了快记录卡时间到了卡死了快的将拉开爱的世界卡死了快记录卡时间到了卡死了快的将拉开爱的世界卡死了快记录卡时间到了卡死了快的将拉开爱的世界卡死了快记录卡时间到了卡死了快的将拉开爱的世界卡死了快记录卡时间到了卡死了快的将拉开爱的世界卡死了快记录卡时间到了卡死了快的将拉开爱的世界卡死了快记录卡时间到了卡死了快的将拉开爱的世界卡死了快记录卡时间到了卡死了快的将拉开爱的世界卡死了快记录卡时间到了卡死了快的将拉开爱的世界卡死了快记录卡时间到了卡死了快的将拉开";
        
    }
    return _textView;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.textView];
//    [self GCD];
}
- (void)GCD{
    //创建队列
    //1.1串行队列创建
    dispatch_queue_t serialQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
    //1.2主队列（是串行的）
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    //2.1并行队列创建
    dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
    //2.2(默认的全局并发队列)
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //创建任务
    // 同步执行任务创建方法（死锁卡住）
//    dispatch_sync(mainQueue, ^{
//        NSLog(@"同步Main队列%@",[NSThread currentThread]);
//    });
    dispatch_sync(serialQueue, ^{
        NSLog(@"同步串行队列%@",[NSThread currentThread]);
    });
    // 异步执行任务创建方法
    dispatch_async(globalQueue, ^{
        NSLog(@"异步global队列%@",[NSThread currentThread]);
    });
    dispatch_async(mainQueue, ^{
        NSLog(@"异步Main队列%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"异步自建队列%@",[NSThread currentThread]);
    });
    
}

- (void)config{
    self.title = @"线程";
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//    [self asyncConcurrent];
//    [self asyncSerial];
//    [self syncConcurrent];
//    [self syncMain];
//     [self deadLock];
//    [self barrierDemo];
    [self groupDemo];
//    [self testMethod];
}
- (void)dealloc{
    NSLog(@"%@释放了",NSStringFromClass([self class]));
}
- (void)testMethod{
//    dispatch_queue_t seriesT = dispatch_queue_create("SYSeariesQueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t seriesT = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
    NSLog(@"任务开始");
    __block NSInteger j = 0;
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        for (NSInteger i = 0; i < 100; i++) {
            NSLog(@"第一个任务%ld",i);
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            self.view.backgroundColor = [UIColor redColor];
            for (NSInteger i = 0; i < 10; i++) {
                NSLog(@"里面的任务%ld",i);
            }
        });
    });
    dispatch_async(seriesT, ^{
        for (NSInteger i = 0; i < 100; i++) {
            NSLog(@"第二个任务%ld",i);
        }
    });
    dispatch_async(seriesT, ^{
        for (NSInteger i = 0; i < 100; i++) {
            NSLog(@"第三个任务%ld",i);
        }
    });
    dispatch_async(seriesT, ^{
         NSLog(@"任务结束");
    });
}

#pragma mark 异步函数 + 并行队列
/*
 *异步函数 + 并行队列
 **开启多条子线程，任务并行执行
 ***不阻塞当前线程
 */
- (void)asyncConcurrent{
    //1.创建并行队列
    NSLog(@"asyncConcurrent--------begin");
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 2.通过异步函数将将任务加入队列
    dispatch_async(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"第一个任务:%ld---%@",i,[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"第二个任务:%ld---%@",i,[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"第三个任务:%ld---%@",i,[NSThread currentThread]);
        }
    });
    // 证明：异步函数添加任务到队列中，任务【不会】立即执行
    //begin-end-任务
    NSLog(@"asyncConcurrent--------end");
}

#pragma mark 异步函数 + 串行队列
/*
 *异步函数 + 串行队列
 **开启一条子线程，任务是有序的在子线程上执行
 ***不阻塞当前线程
 */
- (void)asyncSerial{
     NSLog(@"asyncSerial--------begin");
    dispatch_queue_t serialQueue = dispatch_queue_create("SYQueue", DISPATCH_QUEUE_SERIAL);
    // 2.通过异步函数将任务加入队列
    dispatch_async(serialQueue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"第一个任务:%ld---%@",i,[NSThread currentThread]);
        }
    });
    dispatch_async(serialQueue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"第二个任务:%ld---%@",i,[NSThread currentThread]);
        }
    });
    
    dispatch_async(serialQueue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"第三个任务:%ld---%@",i,[NSThread currentThread]);
        }
    });
    // 证明：异步函数添加任务到队列中，任务【不会】立马执行
    //begin-end-任务
    NSLog(@"asyncSerial--------end");
    
}
#pragma mark 同步函数 + 并行队列
/*
 *同步函数 + 并行队列
 **不会开启子线程，任务是有序执行
 ***在当前线程执行任务。阻塞当前线程
 */
- (void)syncConcurrent{
    NSLog(@"syncConcurrent--------begin");
    // 1.获得全局的并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 2.通过同步函数将任务加入队列
    dispatch_sync(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"第一个任务:%ld---%@",i,[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"第二个任务:%ld---%@",i,[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"第三个任务:%ld---%@",i,[NSThread currentThread]);
        }
    });
    
    // 证明：同步函数添加任务到队列中，任务【立马执行】
    //begin-任务-end
    NSLog(@"syncConcurrent--------end");
}
#pragma mark 同步函数 + 串行队列
/*
 * 同步函数 + 串行队列
 **不会开启线程，任务是有序执行
 ***易发生死锁，使用时要注意
 */
//    下面的用法不会发生死锁，原因分析如下：
//    虽然都是在主线程上执行的，但任务在不同的队列中所以不会发生阻塞
//    syncMain函数是在主队列中
//    其他的任务是在新建的串行队列中
- (void)syncMain{

     NSLog(@"syncMain--------begin");
    // 1.创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
    
    // 2.将任务加入队列
    dispatch_sync(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"1------%ld---%@",i,[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"2------%ld---%@",i,[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"3------%ld---%@",i,[NSThread currentThread]);
        }
    });
     NSLog(@"syncMain--------end");
}

#pragma mark 死锁的情况
- (void)deadLock{
//    ----------------------第一种-----------------
//    使用同步函数在任务执行过程中往任务所在的串行队列中添加任务就会导致任务间互相等待，造成死锁
//    NSLog(@"deadLock--------begin");
//    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_SERIAL);
//    dispatch_sync(queue, ^{
//        NSLog(@"1-----%@", [NSThread currentThread]);
//        // 这里阻塞了
//        dispatch_sync(queue, ^{
//            NSLog(@"2-----%@", [NSThread currentThread]);
//        });
//    });
//    NSLog(@"deadLock--------end");
    
    //    ----------------------第二种-----------------
//    同步函数 dispatch_sync : 立刻执行,并且必须等这个函数执行完才能往下执行
//    主队列特点:凡是放到主队列中的任务,都会放到主线程中执行..如果主队列发现当前主线程有任务在执行,那么主队列会暂停调度队列中的任务,直到主线程空闲为止
//    综合同步函数与主队列各自的特点,不难发现为何会产生死锁的现象,主线程在执行同步函数的时候主队列也暂停调度任务,而同步函数没有执行完就没法往下执行。造成相互等待对方执行完毕。
//    再开一条线程来执行syncMain是不会产生死锁
    NSLog(@"deadLock--------begin");
    // 获得主队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    // 这里阻塞了
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3-----%@", [NSThread currentThread]);
    });
    NSLog(@"deadLock--------end");
}

#pragma mark dispatch_barrier_async使用
/*
 *dispatch_barrier_async
 **必须是并行队列，且不能使用全局的并行队列，实践证明不管用
 ***函数作用：在此函数前面的任务执行完成后此函数才开始执行，在此函数后面的任务等此函数执行完成后才会执行
 */
- (void)barrierDemo
{
    //【不能】使用全局并发队列
    dispatch_queue_t queue = dispatch_queue_create("yanhooQueue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"1------%ld---%@",i,[NSThread currentThread]);
        }
        
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"2------%ld---%@",i,[NSThread currentThread]);
        }
    });
    
    // 在它前面的任务执行结束后它才执行，在它后面的任务等它执行完成后才会执行
    dispatch_barrier_async(queue, ^{
        for (NSInteger i = 0 ; i < 20; i++) {
            NSLog(@"11barrier------%ld---%@",i,[NSThread currentThread]);
        }
    });
//    dispatch_barrier_sync(queue, ^{
//        for (NSInteger i = 0 ; i < 20; i++) {
//            NSLog(@"22barrier------%ld---%@",i,[NSThread currentThread]);
//        }
//    });
    
    dispatch_async(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"3------%ld---%@",i,[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"4------%ld---%@",i,[NSThread currentThread]);
        }
    });
}

#pragma mark dispatch_group使用
/*
 *dispatch_group
 **必须是并行队列才起作用
 需求描述
 现有三个任务：任务A、任务B、任务C
 任务C需要等到任务A和任务B都完成后才执行
 任务A和任务B执行没有先后顺序
 ***函数作用：在此函数前面的任务执行完成后此函数才开始执行，在此函数后面的任务等此函数执行完成后才会执行
 */
- (void)groupDemo
{
    // 创建队列组
    dispatch_group_t group =  dispatch_group_create();
    
    // 获取全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 添加任务A到group
    dispatch_group_async(group, queue, ^{
        // 添加任务A到group
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"A------%ld---%@",i,[NSThread currentThread]);
        }
    });
    UIImageView *iv = [[UIImageView alloc]init];
    
    // 添加任务B到group
    dispatch_group_async(group, queue, ^{
        // 添加任务B到group
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"B------%ld---%@",i,[NSThread currentThread]);
        }
    });
    
    // 当任务A和任务B都执行完后到此来执行任务C
    dispatch_group_notify(group, queue, ^{
        // 如果这里还有基于上面两个任务的结果继续执行一些代码，建议还是放到子线程中，等代码执行完毕后在回到主线程
        // 回到主线程
        for (NSInteger i = 0 ; i < 10; i++) {
            NSLog(@"C------%ld---%@",i,[NSThread currentThread]);
        }
        dispatch_group_async(group, dispatch_get_main_queue(), ^{
            // 执行相关UI显示代码...
            for (NSInteger i = 0 ; i < 10; i++) {
                NSLog(@"主------%ld---%@",i,[NSThread currentThread]);
            }
        });
    });
    

}
@end
